﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace libManagedMessageSystem
{
    public unsafe class NetStream
    {
        private byte*  m_pData;
        private UInt32 m_nLength;
        private UInt32 m_nReadPos;
        private UInt32 m_nWritePos;

        internal void Reset(byte* pData, UInt32 nLength)
        {
            m_pData = pData;
            m_nLength = nLength;
            m_nReadPos = 0;
            m_nWritePos = 0;
        }

        internal void Reset()
        {
            m_nReadPos = 0;
            m_nWritePos = 0;
        }

        internal byte* DataPoint 
        {
            get{return m_pData;}
        }

        public UInt32 ReadLength { get { return m_nReadPos; } }
        public UInt32 WriteLength { get { return m_nWritePos; } }
        public UInt32 DataLength { get { return m_nLength; } }

        public byte ReadByte()
        {
            TryRead(1);
            byte v = m_pData[m_nReadPos];
            m_nReadPos += 1;
            return v;
        }

        public sbyte ReadSByte()
        {
            TryRead(1);
            byte v = m_pData[m_nReadPos];
            m_nReadPos += 1;
            return (sbyte)v;
        }

        public UInt16 ReadUint16()
        {
            TryRead(2);
            UInt16* pData = (UInt16*)(&m_pData[m_nReadPos]);
            m_nReadPos += 2;
            return *pData;
        }

        public Int16 ReadInt16()
        {
            TryRead(2);
            Int16* pData = (Int16*)(&m_pData[m_nReadPos]);
            m_nReadPos += 2;
            return *pData;
        }

        public UInt32 ReadUInt32()
        {
            TryRead(4);
            UInt32* pData = (UInt32*)(&m_pData[m_nReadPos]);
            m_nReadPos += 4;
            return *pData;
        }

        public Int32 ReadInt32()
        {
            TryRead(4);
            Int32* pData = (Int32*)(&m_pData[m_nReadPos]);
            m_nReadPos += 4;
            return *pData;
        }

        public float ReadFloat()
        {
            TryRead(4);
            float* pData = (float*)(&m_pData[m_nReadPos]);
            m_nReadPos += 4;
            return (float)*pData;
        }

        public String ReadString()
        {
            Int32 length = ReadInt32();
            TryRead((UInt32)length);
            sbyte* pData = (sbyte*)(&m_pData[m_nReadPos]);
            m_nReadPos += (UInt32)length;
            return new String(pData, 0, length);
        }

        public void WriteByte(byte v)
        {
            TryWrite(1);
            m_pData[m_nWritePos] = v;
            m_nWritePos += 1;
        }

        public void WriteSByte(sbyte v)
        {
            TryWrite(1);
            m_pData[m_nWritePos] = (byte)v;
            m_nWritePos += 1;
        }

        public void WriteUint16(UInt16 v)
        {
            TryWrite(2);
            UInt16* pData = (UInt16*)(&m_pData[m_nWritePos]);
            *pData = v;
            m_nWritePos += 2;
        }

        public void WriteInt16(Int16 v)
        {
            TryWrite(2);
            Int16* pData = (Int16*)(&m_pData[m_nWritePos]);
            *pData = v;
            m_nWritePos += 2;
        }

        public void WriteUInt32(UInt32 v)
        {
            TryWrite(4);
            UInt32* pData = (UInt32*)(&m_pData[m_nWritePos]);
            *pData = v;
            m_nWritePos += 4;
        }

        public void WriteInt32(Int32 v)
        {
            TryWrite(4);
            Int32* pData = (Int32*)(&m_pData[m_nWritePos]);
            *pData = v;
            m_nWritePos += 4;
        }

        public void WriteFloat(float f)
        {
            TryWrite(4);
            float* pData = (float*)(&m_pData[m_nWritePos]);
            *pData = f;
            m_nWritePos += 4;
        }

        public void WriteString(String s)
        {
            WriteUInt32((UInt32)s.Length);
            for (int i = 0; i < s.Length; ++i)
                WriteByte((byte)s[i]);
        }

        private void TryRead(UInt32 nLength)
        {
            if (nLength + m_nReadPos > m_nLength)
                throw new Exception("TryRead Error");
        }

        private void TryWrite(UInt32 nLenght)
        {
            if (nLenght + m_nWritePos > m_nLength)
                throw new Exception("TryWrite Error");
        }
    }
}
